package com.um.jdy.app.user.manager;

import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.RegexPool;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.internal.util.AlipayEncrypt;
import com.alipay.api.request.AlipaySystemOauthTokenRequest;
import com.alipay.api.request.AlipayUserInfoShareRequest;
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
import com.alipay.api.response.AlipayUserInfoShareResponse;
import com.um.jdy.app.core.configuration.AlipayConfigure;
import com.um.jdy.common.commons.manager.WxManager;
import com.um.jdy.app.core.properties.HshAlipayProperties;
import com.um.jdy.app.core.properties.HshAppProperties;
import com.um.jdy.app.user.entity.dto.*;
import com.um.jdy.app.user.entity.vo.LoginVO;
import com.um.jdy.common.base.enums.YesOrNo;
import com.um.jdy.common.member.entity.po.LoginLog;
import com.um.jdy.common.member.entity.po.MemberUser;
import com.um.jdy.common.member.entity.vo.MemberUserVO;
import com.um.jdy.common.member.enums.MemberEnum;
import com.um.jdy.common.member.service.MemberLoginLogService;
import com.um.jdy.common.member.service.MemberUserService;
import com.um.jdy.common.platform.service.AppService;
import com.um.springboot.starter.code.CommonCode;
import com.um.springboot.starter.exception.ServiceException;
import com.um.springboot.starter.properties.HshProperties;
import com.um.springboot.starter.utils.IdUtils;
import com.um.springboot.starter.utils.JSONUtil;
import com.um.springboot.starter.utils.StringUtil;
import com.um.weixin.mini.service.WxMiniUserService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Map;

/**
 * @Title
 * @Description
 * @Author renjunwei
 * @Date 2023/5/22 10:37
 */
@Slf4j
@Service
public class LoginManager {

    @Autowired
    HshProperties hshProperties;

    @Autowired
    HshAppProperties hshAppProperties;

    @Autowired
    HshAlipayProperties hshAlipayProperties;

    @Autowired
    MemberUserService memberUserService;

    @Autowired
    MemberLoginLogService loginLogService;

    @Autowired
    WxMiniUserService wxMiniUserService;

    @Autowired
    WxManager wxManager;

    @Autowired
    AppService appService;


    /**
     * 检查是否绑定手机号
     * @param openId
     * @return
     */
    public boolean checkPhoneBinded(String openId){
        MemberUser user = memberUserService.getEntity("mini_open_id", openId);
        return null != user && StrUtil.isNotEmpty(user.getMobile()) && ReUtil.isMatch(RegexPool.MOBILE, user.getMobile());
    }

    /**
     * 通过js_code获取微信小程序open_id
     * @param jsCode
     * @return
     */
    public WxMaJscode2SessionResult getWxOpenId(String jsCode) {
        String comId = memberUserService.getComId();

        WxMaJscode2SessionResult sessionInfo = null;
        try {
            sessionInfo = wxManager.getMiniService(comId).getUserService().getSessionInfo(jsCode);
        } catch (WxErrorException e) {
            log.error("获取登录后的session信息错误", e);
            throw new ServiceException(e.getError().getErrorMsg());
        }

        return sessionInfo;
    }

    /**
     * 微信登陆
     * @param param
     * @return
     */
    @Transactional
    public LoginVO wxSignin(WxLoginParam param){
        MemberUser user = memberUserService.getEntity("mini_open_id", param.getOpenId());

        boolean isRegister = false;

        // 创建新用户
        if (user == null) {

            String no = IdUtils.getPrimaryKey();

            if(hshAppProperties.isAutoFillNameAndAvatar()){
                if(StringUtil.isEmpty(param.getNickname()))
                    param.setNickname("微信"+no);

                if(StringUtil.isEmpty(param.getPhoto()))
                    param.setPhoto(hshProperties.getConfig().getDomain() + "/api/v1/static/assets/default-avatar.png");
            }

            user = new MemberUser();
            user.setNo(no);
            user.setMiniOpenId(param.getOpenId());
            user.setUnionId(param.getUnionId());
            user.setPhoto(param.getPhoto());
            user.setNickname(param.getNickname());
            //user.setSex(param.getSex());
            user.setArea(param.getArea());
            user.setCreateTime(DateUtil.date());

            isRegister = true;

        }else if(StrUtil.isNotEmpty(param.getUnionId())){

            // 更新已存在用户的union_id
            user.setUnionId(param.getUnionId());
        }

        user.setUserType(MemberEnum.MemberType.Weixin.name());
        memberUserService.save(user);

        if(MemberEnum.MemberStatus.Disabled.name().equals(user.getStatus())){
            throw new ServiceException(CommonCode.Failed.getCode(), "帐号已禁用");
        }

        //记录登录日志
        LoginLog loginLog = new LoginLog();
        loginLog.setMemberUserId(user.getMemberUserId());
        loginLog.setType("0");
        loginLog.setLoginTime(DateUtil.date());
        loginLogService.save(loginLog);

        LoginVO loginVO = new LoginVO();
        loginVO.setUser(BeanUtil.toBean(user, MemberUserVO.class));
        loginVO.setRegister(isRegister);
        StpUtil.login(user.getMemberUserId());
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        loginVO.setToken(tokenInfo.getTokenValue());
        return loginVO;
    }

    /**
     * 解密微信手机号
     * @param param
     * @return
     */
    public WxMaPhoneNumberInfo wxMobileDecode(WxMobileDecodeParam param) {
        WxMaPhoneNumberInfo phoneNoInfo = wxMiniUserService.getPhoneNoInfo(param.getSessionKey(),
                param.getEncryptedData(), param.getIv());

        return phoneNoInfo;
    }

    /**
     * 支付宝
     * @param param
     * @return
     */
    public String alipayMobileDecode(AliMobileDecodeParam param){

        boolean isDataEncrypted = !param.getEncryptedData().startsWith("{");

        String miniAesEncryptKey = hshAlipayProperties.getAesEncryptKey();

        try {
            //未加密直接返回原内容,否则解密后返回
            String decryptStr = isDataEncrypted ? AlipayEncrypt.decryptContent(param.getEncryptedData(), "AES", miniAesEncryptKey, "UTF-8") : param.getEncryptedData();
            //转为map
            Map decryptMap = JSON.parseObject(decryptStr, Map.class);
            log.info("支付宝解密手机号：{}", decryptMap);
            if ("Success".equals(decryptMap.get("msg"))) {
                return StringUtil.getTrim(decryptMap.get("mobile"));
            } else {
                throw new ServiceException(CommonCode.Failed.getCode(), MapUtil.getStr(decryptMap, "msg"));
            }

        } catch (AlipayApiException e) {
            //解密异常, 记录日志
            log.error("解密支付宝手机号失败", e);
        }

        return "";
    }

    /**
     * 支付宝小程序登录
     * @param param
     * @return
     */
    @Transactional
    public LoginVO alipaySignin(AlipayLoginParam param) {
        String code = param.getCode();

        AlipayClient alipayClient = AlipayConfigure.alipayClient;

        AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
        request.setCode(code);
        request.setGrantType("authorization_code");
        AlipaySystemOauthTokenResponse response = null;
        try {
            response = alipayClient.certificateExecute(request);
        } catch (AlipayApiException e) {
            throw new RuntimeException(e);
        }

        if(!response.isSuccess()) {
            throw new ServiceException(CommonCode.Failed.getCode(), "授权登陆失败");
        }

        Map body = JSONUtil.parseJSONToMap(response.getBody());
        Map alipay_system_oauth_token_response = (Map) body.get("alipay_system_oauth_token_response");

        AlipayUserInfoShareRequest userInfoRequest = new AlipayUserInfoShareRequest();
        AlipayUserInfoShareResponse userInfoResponse = null;
        try {
            userInfoResponse = alipayClient.certificateExecute(userInfoRequest, StringUtil.getTrim(alipay_system_oauth_token_response.get("access_token")));
        } catch (AlipayApiException e) {
            throw new RuntimeException(e);
        }

        if(userInfoResponse.isSuccess()) {
            throw new ServiceException(CommonCode.Failed.getCode(), "授权登陆失败");
        }

        Map userInfoBody = JSONUtil.parseJSONToMap(userInfoResponse.getBody());

        Map userInfo = (Map) userInfoBody.get("alipay_user_info_share_response");
        log.info("支付宝授权登录用户信息: " + userInfo);

        if(StringUtil.getTrim(userInfo.get("code")).equals("10000")) {
            throw new ServiceException(CommonCode.Failed.getCode(), "授权登陆失败");
        }

        String nickname = StringUtil.getTrim(userInfo.get("nick_name"));
        String photo = StringUtil.getTrim(userInfo.get("avatar"));
        MemberUser user = memberUserService.getEntity("alipay_user_id", StringUtil.getTrim(userInfo.get("user_id")));

        if(user == null) {
            user = new MemberUser();
            String no = IdUtils.getPrimaryKey();
            if(StrUtil.isEmpty(nickname)) {
                nickname = "支付宝" + no;
            }
            user.setNo(no);
            user.setAlipayUserId(StringUtil.getTrim(userInfo.get("user_id")));
            user.setCreateTime(DateUtil.date());
        }
        user.setPhoto(photo);
        if(!StrUtil.isEmpty(nickname)) {
            user.setNickname(nickname);
        }

        user.setUserType(MemberEnum.MemberType.Alipay.name());
        memberUserService.save(user);

        if(MemberEnum.MemberStatus.Disabled.name().equals(user.getStatus())){
            throw new ServiceException(CommonCode.Failed.getCode(), "帐号已禁用");
        }

        //记录登录日志
        LoginLog loginLog = new LoginLog();
        loginLog.setMemberUserId(user.getMemberUserId());
        loginLog.setType("0");
        loginLog.setLoginTime(DateUtil.date());
        loginLogService.save(loginLog);

        LoginVO loginVO = new LoginVO();
        loginVO.setUser(BeanUtil.toBean(user, MemberUserVO.class));
        StpUtil.login(user.getMemberUserId());
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        loginVO.setToken(tokenInfo.getTokenValue());
        return loginVO;
    }

    /**
     * 绑定手机号
     * @param param
     */
    public void bindMobile(BindMobileParam param){
        MemberUser user = memberUserService.getEntity(param.getMemberUserId());
        if(null == user){
            throw new ServiceException(CommonCode.Failed.getCode(), "用户不存在");
        }
        user.setMobile(param.getMobile());
        memberUserService.save(user);
    }
}
